﻿
using log4net;
using System;
using System.CodeDom;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Timers;
using ICSharpCode.SharpZipLib.Zip;
using Lb.Common;


namespace Lb.ZipBak
{
    public class SyncDataClient
    {
        private Timer _timer = null;
        private DateTime _syncTime;
        private SettingConfig settingConfig = null;
        private readonly ILog _log = LogManager.GetLogger(
                                         typeof(SyncDataClient));
        public SyncDataClient()
        {
            this._log.Info("初始化定时器备份服务");
            this.settingConfig = XmlHelper.XmlDeserialize<SettingConfig>(SystemParam.ConfigFilePath);
            //计算首次执行时间 毫秒数 
            this._syncTime = this.settingConfig.SyncDate.ObjToDateTime();
            this._timer = new Timer(1000) { AutoReset = true };
            this._timer.Elapsed += this.Timer_SyncData;
            this._log.Info($"起始执行时间：{this._syncTime:s}");
            this._log.Info("初始化定时服务程序完成");

        }
        //备份文件次数
        private int _mSyncCount = 0;
        //备份文件日期
        private string _mSyncDate = "";

        #region 启动和停止服务

        /// <summary>
        /// 启动服务
        /// </summary>
        public void Start()
        {
            this._timer.Start();
        }

        /// <summary>
        /// 停止服务
        /// </summary>
        public void Stop()
        {
            this._timer.Stop();
        }
        #endregion

        #region # 定时器      private void Timer_SyncData(object sender, ElapsedEventArgs e)
        /// <summary> 定时器</summary>
        private void Timer_SyncData(object sender, ElapsedEventArgs e)
        {
            DateTime nowTime = DateTime.Now;
            //检查是否进入更新
            if (nowTime.ToString("yyyy-MM-dd HH:mm:ss") == this._syncTime.ToString("yyyy-MM-dd HH:mm:ss"))
            {
                //设置下次更新时间
                this._syncTime = this.settingConfig.SyncDate.ObjToDateTime().AddDays(this.settingConfig.Day).AddHours(this.settingConfig.Hour)
                    .AddMinutes(this.settingConfig.Minute);

                //更新配置文件
                this.settingConfig.SetSyncTime(this._syncTime);
                this.settingConfig.Update();
                try
                {
                    this._mSyncCount++;
                    string msg = "{0}第{1}次文件备份开始".FormatEx(this._mSyncDate, this._mSyncCount);
                    this._log.Info(msg);
                    if (this._mSyncDate != DateTime.Now.ToString("yyyy-MM-dd"))
                    {
                        this._mSyncDate = DateTime.Now.ToString("yyyy-MM-dd");
                        this._mSyncCount = 1;
                    }
                    //备份文件数据
                    this.SyncOperator();
                    msg = "{0}第{1}次备份完成".FormatEx(this._mSyncDate, this._mSyncCount);

                    this._log.Info(msg);
                }
                catch (Exception ex)
                {
                    this._log.Error("备份文件时出现错误", ex);
                }
                this._log.Info($"下次更新时间：{this._syncTime:s}");

            }
            //如果时间不对，重新设置时间
            if (nowTime > this._syncTime)
            {
                this._syncTime = DateTime.Now.AddSeconds(5);

                //设置下次更新时间
                //this._syncTime = this._syncTime.AddDays(this.settingConfig.Day).AddHours(this.settingConfig.Hour)
                //    .AddMinutes(this.settingConfig.Minute);

                //更新配置文件
                this.settingConfig.SetSyncTime(this._syncTime);
                this.settingConfig.Update();
                this._log.Info($"发现起始时间已经过期，自动设定其实执行日期：{this._syncTime:s}");
                return;
            }

        }

        #endregion

        #region # 备份文件操作
        /// <summary> 备份文件操作</summary>
        public void SyncOperator()
        {
            this._log.Info("开始准备备份。");
            this.CheckDirectory(this.settingConfig.BackDirectoryPath);
            this.ClearFiles();
            this.ZipDataBase();
        }

        /// <summary>
        /// 清理过期文件
        /// </summary>
        private void ClearFiles()
        {
            this._log.Info("检查是否有过期文件，准备清除。");
            string folder = this.settingConfig.BackDirectoryPath;
            string[] filenames = Directory.GetFiles(folder, "*.zip", SearchOption.AllDirectories);
            List<FileInfo> fileinfos = (from x in filenames select new FileInfo(x)).ToList();
            this._log.Info($"检查已经过期的内容，过期的直接删除，备份保留期限：{this.settingConfig.BackupDbYear}");
            DateTime delDate = DateTime.Now.AddYears(-this.settingConfig.BackupDbYear);
            try
            {
                foreach (FileInfo fileinfo in fileinfos.FindAll(p => p.CreationTime < delDate))
                {
                    this._log.Info($"开始删除过期备份文件：{fileinfo.Name}");
                    fileinfo.Delete();
                }

                this._log.Info($"开始检查每月保存一个备份的文件，当前备份前{this.settingConfig.ClearDay}天，数据保留原有设置，之后每月保留一份备份文件。");
                DateTime clearDate = DateTime.Now.AddDays(-this.settingConfig.ClearDay);
                List<DateTime> noDel = new List<DateTime>();
                foreach (FileInfo fileinfo in fileinfos.FindAll(p => p.CreationTime < clearDate).OrderBy(p => p.CreationTime))
                {
                    if (noDel.Exists(p => p.Year == fileinfo.CreationTime.Year && fileinfo.CreationTime.Month == p.Month))
                    {
                        this._log.Info($"开始删除过期备份文件：{fileinfo.Name}");
                        fileinfo.Delete();
                    }
                    else
                    {
                        this._log.Info($"保留每月一份的文件：{fileinfo.Name}");
                        noDel.Add(fileinfo.CreationTime);
                    }
                }
            }
            catch (Exception ex)
            {

                throw new Exception("清空历史文件时出现错误：" + ex.Message, ex);
            }

            this._log.Info("清理过期文件操作完成");
        }

        /// <summary>
        /// 压缩备份文件，压缩完成后删除bak文件，只保留包
        /// </summary>
        /// <returns></returns>
        private void ZipDataBase()
        {
            //扩展名
            string[] exs = this.settingConfig.Extension.Split(',');
            //文件集合
            List<string> fileNames = new List<string>();
            string fileFilter = "";
            foreach (string exitem in exs)
            {
                //拼接需要删除的文件
                fileFilter += "|.*?\\" + exitem;
                fileNames.AddRange(Directory.GetFiles(this.settingConfig.OldDirectory, "*" + exitem).ToList());
            }

            if (!fileNames.Any())
            {
                this._log.Info("没有发现需要备份的文件,本次压缩将被取消。");
                return;
            }

            fileFilter = fileFilter.Trim('|');
            string saveFileName = Path.GetFileName(this.settingConfig.OldDirectory);
            saveFileName = DateTime.Now.ToString(this.settingConfig.NameRegulation).Replace("{文件名}", Path.GetFileName(saveFileName));
            //如果只有一个文件，去文件名
            if (fileNames.Count == 1)
            {
                saveFileName = DateTime.Now.ToString(this.settingConfig.NameRegulation).Replace("{文件名}", Path.GetFileName(fileNames[0]));
            }

            saveFileName = Path.Combine(this.settingConfig.BackDirectoryPath, saveFileName + ".zip");
            this._log.Info($"开始压缩文件，文件名{saveFileName}。");
            if (fileFilter == ".*?\\.bak")
            {
                fileFilter = fileFilter;
            }
            new FastZip().CreateZip(saveFileName, this.settingConfig.OldDirectory, false, fileFilter);
            this._log.Info($"压缩文件完成，压缩包地址：{saveFileName},开始准备删除备份前文件。");



            try
            {
                foreach (string fileName in fileNames)
                {
                    this._log.Info($"开始准备删除文件：{fileName}。");
                    File.Delete(fileName);
                    this._log.Info($"删除历史文件完成，历史文件：{fileName}。");
                }
            }
            catch (Exception ex)
            {
                throw new Exception("删除压缩前文件错误：" + ex.Message, ex);
            }

        }


        /// <summary>
        /// 检查备份目录是否存在
        /// </summary>
        private void CheckDirectory(string dirName)
        {
            if (!Directory.Exists(dirName))
            {
                this._log.Info($"发现备份目录不存在，开始创建目录,目录:{dirName}");
                Directory.CreateDirectory(dirName);

            }
        }
        #endregion
        /// <summary>
        /// 上传数据
        /// </summary>
        /// <param name="fileName"></param>
        private void UploadBaiduPan(string fileName)
        {


        }

    }
}
